#define _CRT_SECURE_NO_WARNINGS 1

//#include <stdio.h>
//#include <stdlib.h>
//#include <assert.h>
//#include <ctype.h>//isspace isdigit
//#include <limits.h>//INT_MAX  INT_MIN
//enum State
//{
//    INVALID,
//        VALID
//}state=INVALID;//初始化为invalid 非法的，无效的
//int my_atoi(const char* str)
//{
//    int flag = 1;
//    assert(str != NULL);//空指针
//    if (*str == '\0')//空字符串
//    {
//        return 0;
//    }
//    while (isspace(*str))//字符串中的空格
//    {
//        str++;
//    }
//    if (*str == '-') //正负号问题
//    {
//        flag = -1;
//        str++;
//    }
//    if (*str == '+')
//    {
//        flag = 1;
//        str++;
//    }
//	long long n = 0;
//	while (*str != '\0')
//	{
//        if (isdigit(*str))//数字字符
//        {
//            n = n * 10 + (*str - '0');
//            if (n > INT_MAX || n < INT_MIN)//5.溢出问题
//            {
//                break;
//            }
//        }
//        else//不是数字字符直接跳出循环，state此时还是INVALID
//        {
//            break;
//        }
//        str++;
//	}
//    if (*str == '\0')
//    {
//        state = VALID;
//    }
//    return (int)(n*flag);
//}
//int main()
//{
//    char arr[50] = "   -123a5";
//    //int n = atoi(arr);
//    int n = my_atoi(arr);
//    //判断合法非法转换
//    if (state == VALID)
//    {
//        printf("合法转化：n = %d\n", n);
//    }
//    else
//    {
//        printf("非法转换：n = %d\n", n);
//    }
//    return 0;
//}

//模拟实现strncpy
//#include<stdio.h>
//#include<string.h>
//#include<assert.h>
//char* my_strcpy(char* dest, const char* src,int n)
//{
//    assert(dest != NULL);
//    assert(src != NULL);
//    char* ret = dest;//让ret指向dest的起始地址
//    int i = 0;
//    for (i = 0;i < n && src[i];i++)
//    {
//        dest[i] = src[i];
//    }
//    if (i < n)
//    {
//        dest[i] = '\0';
//    }
//    return ret;
//}
//int main()
//{
//    char arr1[30] = "##########################";
//    char arr2[] = "hello world";
//    //printf("%s\n", strncpy(arr1, arr2,5));
//    printf("%s\n", my_strcpy(arr1, arr2,5));
//    return 0;
//}

//模拟实现strncat
//#include<stdio.h>
//#include<string.h>
//#include<assert.h>
//char* my_strncat(char* dest, const char* src,int n)
//{
//    assert(dest != NULL);
//    assert(src != NULL);
//    char* ret = dest;//让ret指向dest的起始地址
//    while (*dest)//找到'\0'  '\0'的ASCII码为0跳出循环
//    {
//        dest++;
//    }
//    int i = 0;
//    for (i = 0;i < n && src[i];i++)
//    {
//        dest[i] = src[i];
//    }
//    if (i < n)
//    {
//        dest[i] = '\0';
//    }
//    return ret;
//}
//int main()
//{
//    char arr1[20] = "hello ";
//    char arr2[] = "world";
//    //printf("%s\n", strncat(arr1, arr2,3));
//    printf("%s\n", my_strncat(arr1, arr2,3));
//    return 0;
//}

//找一个单身狗
//【题目内容】
//一个数组中只有一个数字是出现一次，其他所有数字都出现了两次。
//编写一个函数找出这两个只出现一次的数字。
//#include<stdio.h>
//#include<string.h>
//int find_dog(int arr[],int sz)
//{
//	int dog = 0;
//	for (int i = 0;i < sz;i++)
//	{
//		dog ^= arr[i];
//	}
//	return dog;
//}
//int main()
//{
//	int arr[] = { 1,2,2,3,3,4,1 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	printf("单身狗是%d", find_dog(arr,sz));
//	return 0;
//}

//找两个单身狗
//一个数组中只有两个数字是出现一次，其他所有数字都出现了两次。
//编写一个函数找出这两个只出现一次的数字。
//#include<stdio.h>
//void find_two_dog(int arr[],int sz,int* px,int* py)
//{
//	int sum = 0;
//	for (int i = 0; i < sz; i++)
//	{
//		sum ^= arr[i];
//	}
//	int count = 0;
//	for (int i = 0; i < 32; i++)
//	{
//		if (sum & 1 << i) //循环判断第几位是1
//		{
//			count = i;//如果是1 记录下来
//			break;
//		}
//	}
//	int dog1 = 0, dog2 = 0;
//	for (int i = 0; i < sz; i++)
//	{
//		if (arr[i] & 1 << count)
//		{
//			dog1 ^= arr[i];
//		}
//		else
//		{
//			dog2 ^= arr[i];
//		}
//	}
//	*px = dog1;
//	*py = dog2;
//}
//int main()
//{
//	int arr[] = { 1,2,3,3,1,4 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	int x = 0, y = 0;//因为不能return两个值，所以设置两个返回型参数
//	find_two_dog(arr, sz, &x, &y);
//	printf("第一个单身狗%d\n第二个单身狗%d",x, y);
//	return 0;
//}

//写一个宏，可以将一个整数的二进制位的奇数位和偶数位交换。

//#include<stdio.h>      //a  1010                   5  0101
//#define SWAP(R) (((R) & 0xaaaaaaaa)>>1) + (((R) & 0x55555555)<<1)
//int main()
//{
//    int a = 10;
//	printf("%d\n", SWAP(a));
//	return 0;
//}

//offsetof宏的模拟实现
#include <stdio.h>
#include <stddef.h>
//结构体起始地址加上该成员相对于起始地址的偏移量就是成员变量的地址。
//想要知道成员相对于结构体起始地址的偏移量，假设结构体起始地址位于0地址处，
//那么结构体成员变量的地址强制类型转换为size_t后就相当于该成员相对于起始地址的偏移量
#define OFFSETOF(type, member) (size_t)(&(((type*)0)->member))//-0忽略了
struct S 
{
	int a;//0 1 2 3
	char b;//4
	//5
	short c;//6  7
};
int main() 
{
	printf("%d\n", offsetof(struct S, a));
	printf("%d\n", offsetof(struct S, b));
	printf("%d\n", offsetof(struct S, c));

	printf("%d\n", OFFSETOF(struct S, a));
	printf("%d\n", OFFSETOF(struct S, b));
	printf("%d\n", OFFSETOF(struct S, c));
	return 0;
}